using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI;
using System.IO;
using System.Reflection;
using System.Web.UI.WebControls;
using System.Drawing;

using GURUCORE.Framework.Core;
using GURUCORE.Lib.Core;

using GURUCORE.Lib.Core.Reflection;

using GURUCORE.Framework.Core.Util;
using GURUCORE.Framework.Core.Data;
using GURUCORE.Portal.Service.Business.DTO;


namespace GURUCORE.Portal.Core
{	
	public class Pagelet : UserControl
	{
		private PageContext m_oPageContext;
        public PageContext PageContext
        {
            get            {                return m_oPageContext;            }
            set            {                m_oPageContext = value;            }
        }

		private int m_nPageletID;			//in database
        public int PageletID
        {
            set { m_nPageletID = value; }
            get { return m_nPageletID; }
        }

        private string m_sPageletUniqueID;	//in page context
        public string PageletUniqueID
        {
            set { m_sPageletUniqueID = value; }
            get { return m_sPageletUniqueID; }
        }

        private string m_sPageletName;		//
        public string PageletName
        {
            get { return m_sPageletName; }
        }



        #region HACK: from 10/10/2007, no need these vars, if they are here too long after hack day, delete it.
        //private string m_sPageletTitle;
        //public string PageletTitle
        //{
        //    get { return m_sPageletTitle; }
        //    set { m_sPageletTitle = value; }
        //}
        #endregion


        #region GURUCORE API for other to interact with Framework

        private string m_sRootURL;
        /// <summary>
        /// GAPI
        /// </summary>
        public string RootURL
        {
            get
            {
                return m_sRootURL;
            }
            set
            {
                m_sRootURL = value;
            }
        }

        private string m_sPageExtension;
        /// <summary>
        /// GAPI
        /// </summary>
        public string PageExtension
        {
            get { return m_sPageExtension; }
            set { m_sPageExtension = value; }
        }

        private string m_sTheme;
        /// <summary>
        /// GAPI
        /// </summary>
		public string Theme
		{
			get { return m_sTheme; }
			set { m_sTheme = value; }
		}

        /// <summary>
        /// URL from root, without trailling /. Eg: http://gurucore.com/Theme/Silver ---> URL to Silver theme
        /// </summary>
        public string ThemeURL
        {
            get { return RootURL + CONST.THEME_FOLDER + "/" + Theme; }
        }

        private Hashtable m_htParameter;
        /// <summary>
        /// GAPI
        /// </summary>
        public Hashtable Parameter
        {
            get
            {
                return m_htParameter;
            }
            set
            {
                m_htParameter = value;
            }
        }

        private Hashtable m_htConfiguration;
        /// <summary>
        /// GAPI
        /// </summary>
        public Hashtable Configuration
        {
            get
            {
                return m_htConfiguration;
            }
            set
            {
                m_htConfiguration = value;
            }
        }
               
        private VwPageDefinitionDTO m_dtoPageletDefine;
        /// <summary>
        /// GAPI
        /// </summary>
        public VwPageDefinitionDTO PageletDefine
        {
            set
            {
                m_dtoPageletDefine = value;
            }
            get
            {
                return m_dtoPageletDefine;
            }

        }


        #endregion


      

        // ------------> PAGELET COMPONENT MODEL - for implemented pagelet access and interact
        private Control m_PageletBody;
        private Control m_PageletBodyDivWrap;
        private Control m_PageletControlBar;
        private Control m_PageletTitle;
        private Control m_PageletControlButton;
        
        public Control PageletBody
        {
            get { return m_PageletBody; }
            set { m_PageletBody = value; }

        }
        public Control PageletBodyDivWrap
        {
            get { return m_PageletBodyDivWrap; }
            set { m_PageletBodyDivWrap = value; }
        }
        public Control PageletControlBar
        {
            get { return m_PageletControlBar; }
            set { m_PageletControlBar = value; }
        }
        public Control PageletTitleControl
        {
            get { return m_PageletTitle; }
            set { m_PageletTitle = value; }
        }
        public Control PageletControlButton
        {
            get { return m_PageletControlButton; }
            set { m_PageletControlButton = value; }
        }
        // ------------> PAGELET COMPONENT MODEL - for implemented pagelet access and interact






        // ------------> PUBLIC COMMON IN PARAM - all pagelets will have these Config-InParameter
        [PageletInParam("ItemPerPage", PageletInParamAttribute.PAGE_CONFIGURATION_PARAM_SOURCE)]
        protected int m_nItemPerPage;
        [PageletInParam("RewriteTitle", PageletInParamAttribute.PAGE_CONFIGURATION_PARAM_SOURCE)]
        protected int m_nRewriteTitle;
        // ------------> PUBLIC COMMON IN PARAM - all pagelets will have these Config-InParameter





		
		const string CACHE_PAGELET_SESSIONFUL_MEMBER = "CachePageletSessionfulMember";
        public const string ACTION_HOME = "Home";
        public const string ACTION_ACCESSDENIED = "AccessDenied";



#if (OPTIMIZING) // OPTIMIZING
        DateTime dtmPageletTimeStart = DateTime.Now;
        string myString = " * ";
        string sPageRenderEngineMessage = "PageRenderEngineMessage in PageController (DEBUG mode only): ";
#endif


		public Pagelet()
		{
			this.Init += new EventHandler(Pagelet_Init);
			this.Load += new EventHandler(Pagelet_Load);         
			this.PreRender += new EventHandler(Pagelet_PreRender);

			m_sPageletName = this.GetType().BaseType.FullName;
		}

			

        // ---------------> PAGELET LIFECYCLE

		private void Pagelet_Init(object sender, EventArgs e)
        {
            m_htControl2DTOMapper = SetupControl2DTOMapper();
			m_htDTO2ControlMapper = SetupDTO2ControlMapper();

			//resolve all relative path

			//restore session fields
			Hashtable htSessionField;
			if (HttpRuntime.Cache[CACHE_PAGELET_SESSIONFUL_MEMBER + "#" + this.GetType().FullName] != null)
			{
				htSessionField = (Hashtable)HttpRuntime.Cache[CACHE_PAGELET_SESSIONFUL_MEMBER + "#" + this.GetType().FullName];
			}
			else
			{
				//reflec to get all sessionful member
				Type tThis = this.GetType().BaseType;
				FieldInfo[] arrField = tThis.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);

				htSessionField = new Hashtable();
				foreach (FieldInfo oField in arrField)
				{
					object[] arrAttr = oField.GetCustomAttributes(typeof(PageletSessionfulMemberAttribute), false);
					if (arrAttr.Length > 0)
					{
						string sKey = ((PageletSessionfulMemberAttribute)arrAttr[0]).Name;
						if (sKey == string.Empty)
						{
							htSessionField.Add(oField.Name, oField);
						}
						else
						{
							htSessionField.Add(sKey, oField);
						}
						
					}
				}

				//cache it
				HttpRuntime.Cache.Insert(CACHE_PAGELET_SESSIONFUL_MEMBER + "#" + this.GetType().FullName, htSessionField, null, DateTime.MaxValue, TimeSpan.Zero);
			}

			//restore value from session
			foreach (DictionaryEntry oEntry in htSessionField)
			{
				FieldInfo oField = (FieldInfo)oEntry.Value;
				oField.SetValue(this, Session[oEntry.Key.ToString()]);
			}

			//set title


			OnPageletInit();



#if (OPTIMIZING) // OPTIMIZING
            string myString = string.Format("<b>{0}</b> - Pagelet.Init {1} - {2}ms<br>",  
                this.PageletDefine.ClassName, 
                this.PageletUniqueID, 
                DateTime.Now.Subtract(dtmPageletTimeStart).TotalMilliseconds);
            Response.Write(myString);
#endif
        }		

       



		protected virtual void OnPageletInit()
		{
		}


     

		

        protected override void OnLoad(EventArgs e)
        {
#if (OPTIMIZING) // OPTIMIZING
            myString += string.Format("<b>{0}</b> - Pagelet.OnLoad {1} - {2}ms    ----   ",
                this.PageletDefine.ClassName,
                this.PageletUniqueID,
                DateTime.Now.Subtract(dtmPageletTimeStart).TotalMilliseconds);            
#endif
            base.OnLoad(e);
        }

        private void Pagelet_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                OnPageletLoad();
            }
            else
            {
                OnPageletPostBack();
            }

            // HACK: add meta support implement for framework.
            /// OnPageletMeta is function where Pagelet provide it information for the framework environment
            /// these information can be use by other pagelet
            /// these information will make other pagelets detect this pagelet existance in the framework environment (in the page)
            OnMetaInit();

#if (OPTIMIZING) // OPTIMIZING
            myString += string.Format("<b>{0}</b> - Pagelet.Pagelet_Load {1} - {2}ms<br>",
                string.Empty,
                this.PageletUniqueID,
                DateTime.Now.Subtract(dtmPageletTimeStart).TotalMilliseconds);
            Response.Write(myString);
#endif
        }

        protected virtual void OnPageletLoad()
        {
        }
        protected virtual void OnPageletPostBack()
        {
        }




        #region META Orient environment data
        private string m_sMainEntityIDParamName;
        public string MainEntityIDParamName
        {
            get { return m_sMainEntityIDParamName; }
            set { m_sMainEntityIDParamName = value; }
        }

        [PageletInParam(PageletInParamAttribute.URL_PARAM_SOURCE, URL_PARAM_ID, true, true)]
        private int m_nMainEntityRecordID;
        public int MainEntityRecordID
        {
            get { return m_nMainEntityRecordID; }
            set { m_nMainEntityRecordID = value; }
        }
        private object m_oMainEntity;
        public object MainEntity
        {
            get { return m_oMainEntity; }
            set { m_oMainEntity = value; }
        }

        #endregion META Orient environment data

        /// <summary>
        /// this constant is for URL, for user, not for framework
        /// </summary>
        public const string URL_PARAM_ID = "ID";
        public const string META_PARAM_ENTITY = "__MainEntity_Entity";
        public const string META_PARAM_RECORDID_FIELDNAME = "__MainEntity_FieldName";
        public const string META_PARAM_RECORDID = "__MainEntity_RecordID";

        /// <summary>
        /// this function will call right after pagelet loaded.
        /// You should do these thing: add meta Entity info to PageContext
        /// </summary>
        protected virtual void OnMetaInit()
        {
            if (null != m_oMainEntity)
            {
                if (!m_oPageContext.ContainsKey(META_PARAM_ENTITY))
                {
                    m_oPageContext.Add(META_PARAM_ENTITY, m_oMainEntity);
                }
                else
                {
                    m_oPageContext[META_PARAM_ENTITY] = m_oMainEntity;
                }
            }


            if (default(string) != m_sMainEntityIDParamName && string.Empty != m_sMainEntityIDParamName)
            {
                if (!m_oPageContext.ContainsKey(META_PARAM_RECORDID_FIELDNAME))
                {
                    m_oPageContext.Add(META_PARAM_RECORDID_FIELDNAME, m_sMainEntityIDParamName);
                }
                else
                {
                    m_oPageContext[META_PARAM_RECORDID_FIELDNAME] = m_sMainEntityIDParamName;
                }
            }


            if (default(int) != m_nMainEntityRecordID)
            {
                if (!m_oPageContext.ContainsKey(META_PARAM_RECORDID))
                {
                    m_oPageContext.Add(META_PARAM_RECORDID, m_nMainEntityRecordID);
                }
                else
                {
                    m_oPageContext[META_PARAM_RECORDID] = m_nMainEntityRecordID;
                }
            }

        }

		protected virtual void OnPageletPreRender()
		{
        }

        protected override void OnPreRender(EventArgs e)
        {
#if (OPTIMIZING) // OPTIMIZING
            string myString = string.Format("Pagelet.OnPreRender <b>{0}</b> - {1} - {2}ms  -----  ",
                string.Empty,
                this.PageletUniqueID,
                DateTime.Now.Subtract(dtmPageletTimeStart).TotalMilliseconds);
            Response.Write(myString);
#endif
            base.OnPreRender(e);
        }

        private void Pagelet_PreRender(object sender, EventArgs e)
        {
            // TODO: GURUCORE: TIME CONSUME, maybe not needed, resolve relative path in html tag
            string sSubFolder = string.Empty;
            if (m_dtoPageletDefine.TemplateFile.LastIndexOf("/") >= 0)
            {
                sSubFolder = System.IO.Path.GetDirectoryName(m_dtoPageletDefine.TemplateFile) + "/";
                // HACK: sSubFolder = m_dtoPageletDefine.TemplateFile.Substring(0, m_dtoPageletDefine.TemplateFile.LastIndexOf("/")) + "/";
            }
            if (sSubFolder == string.Empty)
            {
                sSubFolder = "/";
            }


            Stack<Control> stkControl = new Stack<Control>();
            foreach (Control oCtrl in this.Controls)
            {
                stkControl.Push(oCtrl);
            }

            while (stkControl.Count > 0)
            {
                Control oCtrl = stkControl.Pop();
                //process scr attribute for img, href for other
                if (oCtrl is System.Web.UI.HtmlControls.HtmlImage)
                {
                    System.Web.UI.HtmlControls.HtmlImage imgCtrl = (System.Web.UI.HtmlControls.HtmlImage)oCtrl;
                    //check if use relative
                    if (!imgCtrl.Src.StartsWith("http://"))
                    {
                        imgCtrl.Src = RootURL + "Theme/" + m_sTheme + "/Module/" + m_dtoPageletDefine.ModuleName + "/" + sSubFolder + imgCtrl.Src;
                    }
                }
                else if (oCtrl is System.Web.UI.HtmlControls.HtmlTableCell)
                {
                    System.Web.UI.HtmlControls.HtmlTableCell tdCtrl = (System.Web.UI.HtmlControls.HtmlTableCell)oCtrl;
                    string sBackGround = tdCtrl.Style["background-image"];
                    if ((sBackGround != null) && (sBackGround.Trim().StartsWith("url(")))
                    {
                        tdCtrl.Style["background-image"] = "url(" + RootURL + "Theme/" + m_sTheme + "/Module/" + m_dtoPageletDefine.ModuleName + "/" + sSubFolder + tdCtrl.Style["background-image"].Substring(4);
                    }
                }
                else if (oCtrl is System.Web.UI.WebControls.Image)
                {
                    System.Web.UI.WebControls.Image btnCtrl = (System.Web.UI.WebControls.Image)oCtrl;
                    //check if use relative
                    if (!btnCtrl.ImageUrl.StartsWith("http://"))
                    {
                        btnCtrl.ImageUrl = RootURL + "Theme/" + m_sTheme + "/Module/" + m_dtoPageletDefine.ModuleName + "/" + sSubFolder + btnCtrl.ImageUrl;
                    }
                }

                foreach (Control oSubCtrl in oCtrl.Controls)
                {
                    stkControl.Push(oSubCtrl);
                }
            }


            OnPageletPreRender();

            //store session fields
            Hashtable htSessionField;
            if (HttpRuntime.Cache[CACHE_PAGELET_SESSIONFUL_MEMBER + "#" + this.GetType().FullName] != null)
            {
                htSessionField = (Hashtable)HttpRuntime.Cache[CACHE_PAGELET_SESSIONFUL_MEMBER + "#" + this.GetType().FullName];
            }
            else
            {
                //reflec to get all sessionful member
                Type tThis = this.GetType().BaseType;
                FieldInfo[] arrField = tThis.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);

                htSessionField = new Hashtable();
                foreach (FieldInfo oField in arrField)
                {
                    object[] arrAttr = oField.GetCustomAttributes(typeof(PageletSessionfulMemberAttribute), false);
                    if (arrAttr.Length > 0)
                    {
                        string sKey = ((PageletSessionfulMemberAttribute)arrAttr[0]).Name;
                        if ((null != sKey) && (sKey != string.Empty))
                        {
                            htSessionField.Add(sKey, oField);
                        }
                        else
                        {
                            htSessionField.Add(oField.Name, oField);
                        }
                    }
                }

                //cache it
                HttpRuntime.Cache.Insert(CACHE_PAGELET_SESSIONFUL_MEMBER + "#" + this.GetType().FullName, htSessionField, null, DateTime.MaxValue, TimeSpan.Zero);
            }


            //store values into session
            foreach (DictionaryEntry oEntry in htSessionField)
            {
                FieldInfo oField = (FieldInfo)oEntry.Value;
                Session[oEntry.Key.ToString()] = oField.GetValue(this);
            }




#if (OPTIMIZING) // OPTIMIZING
            string myString = string.Format("Pagelet.PreRender <b>{0}</b> - {1} - {2}ms<br>",
                this.PageletDefine.ClassName,
                this.PageletUniqueID,
                DateTime.Now.Subtract(dtmPageletTimeStart).TotalMilliseconds);
            Response.Write(myString);
#endif
        }


        protected override void OnUnload(EventArgs e)
        {
#if (OPTIMIZING) // OPTIMIZING
            string myString = string.Format("Pagelet.OnUnLoad <b>{0}</b> - {1} - {2}ms<br>",
                this.PageletDefine.ClassName,
                this.PageletUniqueID,
                DateTime.Now.Subtract(dtmPageletTimeStart).TotalMilliseconds);
            Trace.Write(myString);
#endif
            base.OnUnload(e);
        }








        #region Create Thumbnail Image

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p_sFileName"></param>
        /// <param name="p_sRelativePath"></param>
        /// <param name="p_bLocalized"></param>
        /// <param name="p_arrThumbnailSize"></param>
        /// <returns></returns>
        protected string CreateThumbnailImage(string p_sFileName, string p_sRelativePath, bool p_bLocalized, params string[] p_arrThumbnailSize)
        {
            return CreateThumbnailImage(p_sFileName, default(string), p_sRelativePath, p_bLocalized, p_arrThumbnailSize);
        }

        /// <summary>
        ///    1@@ get the full filepath (from portal ModuleData folder).
        ///    2@@ check provided thumbnail size. if not good, return string.Empty.
        ///    3@@ check file existed, if not good, return string.Empty.
        ///    4@@ try load image from filepath, if not good it means file is not image, return exception Message (not raise Exception).
        ///    5@@ if everything OK, foreach thumbnail size, do delete old thumb (if existed) and create new one. if can not delete old thumbnail, ignore that size.
        /// </summary>
        /// <param name="p_sFileName"></param>
        /// <param name="p_sModuleName">if default(string), current module will take to store thumb</param>
        /// <param name="p_sRelativePath"></param>
        /// <param name="p_bLocalized"></param>
        /// <param name="p_arrThumbnailSize">array of string, in WIDTHxHEIGHT format. Unit is pixel. Eg: 320x320,640x480</param>
        /// <returns></returns>
        protected string CreateThumbnailImage(string p_sFileName, string p_sModuleName, string p_sRelativePath, bool p_bLocalized, params string[] p_arrThumbnailSize)
        {
            // physical root
            string sRoot = System.Web.HttpRuntime.AppDomainAppPath;
            string sDataDirectory = GetModuleDataDirectory(p_sModuleName, p_sRelativePath, p_bLocalized);

            System.Drawing.Image oOriginalImg = null;

            if ((p_arrThumbnailSize != null) && (p_arrThumbnailSize.Length > 0))
            {
                if (System.IO.File.Exists(sRoot + sDataDirectory + p_sFileName))
                {
                    try
                    {
                        oOriginalImg = System.Drawing.Image.FromFile(sRoot + sDataDirectory + p_sFileName);
                    }
                    catch (Exception ex)
                    {
                        // GException.ProcessException("ExternalData error, image is not image-type", ex);

                        // the provided original image filename is not image type, we do not process anymore, do not create thumbnail for it
                        return ex.Message;
                    }
                }
                else
                {
                    return string.Empty; // do not create thumbnail with non-existed file
                }
            }
            else
            {
                return string.Empty; // you do not provided thumbnail size, so we do not do anything
            }


            foreach (string sThumbnailSize in p_arrThumbnailSize)   // create thumbnail for each size provided
            {
                int nThumbWidth = 0;
                int nThumbHeight = 0;

                if (sThumbnailSize.IndexOf('x') > 0)
                {
                    string[] arrSize = sThumbnailSize.Split('x');
                    nThumbWidth = ConvertSafe.ToInt32(arrSize[0]);
                    nThumbHeight = ConvertSafe.ToInt32(arrSize[1]);
                }

                if (nThumbWidth == 0 && nThumbHeight == 0)
                {
                    continue;
                }

                if (nThumbWidth == 0)
                {
                    nThumbWidth = Convert.ToInt32(
                        oOriginalImg.Width * ((double)nThumbHeight / oOriginalImg.Height)
                        );
                }

                if (nThumbHeight == 0)
                {
                    nThumbHeight = Convert.ToInt32(
                        oOriginalImg.Height * ((double)nThumbWidth / oOriginalImg.Width)
                        );
                }


                /// rotate 360degrees, to make the thumbnail better
                /// Upon further looking at Microsoft's documentation I found the cause of the problem. 
                /// The problem is that the GetThumbNailImage() method resizes an image from the original image if their is no thumbnail embedded in the image. 
                /// The problem is, most digital cameras do embed a thumbnail image in the image. 
                /// So, what's happening is that the tiny thumbnail image embedded in the picture is being sized from something like 32x12 to 400x300 which gives the horrible picture quality. Just an FYI.
                /// 4Guys enthusiast Doug P. chimes in with a workaround:
                /// I've found that if you rotate the original image 360 degrees it solves this problem. 
                /// I guess rotating the image causes it to lose the embedded thumbnail and the full size image is then resized when the GetThumbnailImage() method is called. 
                /// Give it a try, just add in the following code right before you call the GetThumbnailImage() method:                
                oOriginalImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
                oOriginalImg.RotateFlip(RotateFlipType.Rotate180FlipNone);
                                
                if (GURUCORE.Lib.Core.File.StrongDeleteFileSafe(sRoot + sDataDirectory + sThumbnailSize + p_sFileName))
                {
                    System.Drawing.Image oThumbnail = oOriginalImg.GetThumbnailImage(nThumbWidth, nThumbHeight, new System.Drawing.Image.GetThumbnailImageAbort(dummyGetThumbnailImageAbortCallback), IntPtr.Zero);
                    oThumbnail.Save(sRoot + sDataDirectory + sThumbnailSize + p_sFileName);
                }

            }   // END: create thumbnail for each size provided

            return p_sFileName;
        }
        /// <summary>
        /// Dummy callback delegate for create thumbnail file
        /// </summary>
        /// <returns></returns>
        private bool dummyGetThumbnailImageAbortCallback()
        {
            return false;
        }

        #endregion


        #region URL Data path

        /// <summary>
        /// return current module (in URL string) data directory (from URL root) with locale sensitive
        /// </summary>
        /// <returns></returns>
        protected string GetModuleDataDirectory(string p_sModuleName, string p_sRelativePath, bool p_bLocalized)
        {
            string sModuleName = string.IsNullOrEmpty(p_sModuleName) ? m_dtoPageletDefine.ModuleName : p_sModuleName;
            string sLocale = "default";

            if (p_bLocalized)
            {
                sLocale = GURUCORE.Framework.Core.GApplication.GetInstance().GetApplicationLocale();
            }

            if (string.IsNullOrEmpty(p_sRelativePath))
            {
                return "Data/Module/" + sModuleName + "/" + sLocale + "/";                
            }
            else
            {
                return "Data/Module/" + sModuleName + "/" + p_sRelativePath + "/" + sLocale + "/";                
            }

        }


        /// <summary>
        /// ROOT
        /// </summary>
        /// <param name="p_sModuleName">ModuleName</param>
        /// <param name="p_sRelativePath">Relative path, from the Module's data folder</param>
        /// <param name="p_sFilename"></param>
        /// <param name="p_blnLocalized">Get from localized location or not</param>
        /// <returns></returns>
        protected string GetDataLink(string p_sModuleName, string p_sRelativePath, string p_sFilename, bool p_blnLocalized)
        {
            return m_sRootURL + GetModuleDataDirectory(p_sModuleName, p_sRelativePath, p_blnLocalized) + p_sFilename;
        }
        /// <summary>
        /// OVERLOAD
        /// </summary>
        /// <param name="p_sRelativePath">Relative path, from the Module's data folder</param>
        /// <param name="p_sFilename"></param>
        /// <param name="p_blnLocalized">Get from localized location or not</param>
        /// <returns></returns>
        protected string GetDataLink(string p_sRelativePath, string p_sFilename, bool p_blnLocalized)
        {
            return GetDataLink(default(string), p_sRelativePath, p_sFilename, p_blnLocalized);
        }


        #endregion


        #region Common use util function in pagelet
        
        protected Control FindControlRecursive(string p_sID)
        {
            Stack<INamingContainer> stkContainer = new Stack<INamingContainer>();
            stkContainer.Push(this);
            Control ctrlResult;
            while (stkContainer.Count > 0)
            {
                INamingContainer oContainer = stkContainer.Pop();
                ctrlResult = ((Control)oContainer).FindControl(p_sID);
                if (ctrlResult != null)
                {
                    return ctrlResult;
                }
                else
                {
                    foreach (Control ctrlSub in ((Control)oContainer).Controls)
                    {
                        if (ctrlSub is INamingContainer)
                        {
                            stkContainer.Push(ctrlSub as INamingContainer);
                        }
                    }
                }
            }
            return null;
        }



        /// <summary>
        /// UTIL - change the pagelet text in PageletTitle only
        /// </summary>
        /// <param name="p_sTitle"></param>
        protected void SetPageletTitle(string p_sTitle)
        {
            if (null != (m_PageletTitle as ITextControl))
            {
                (m_PageletTitle as ITextControl).Text = p_sTitle;
            }

            else if (null != (m_PageletTitle as System.Web.UI.HtmlControls.HtmlGenericControl))
            {
                (m_PageletTitle as System.Web.UI.HtmlControls.HtmlGenericControl).InnerText = p_sTitle;
            }
        }
        /// <summary>
        /// UTIL - set the new control display in the PageletTitle
        /// </summary>
        /// <param name="p_oCtrl"></param>
        protected void SetPageletTitle(Control p_oCtrl)
        {
            if (null != p_oCtrl && null != m_PageletTitle)
            {
                p_oCtrl.ID = m_PageletTitle.ID;
                m_PageletTitle.Parent.Controls.Add(p_oCtrl);
                m_PageletTitle.Parent.Controls.Remove(m_PageletTitle);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="p_sRelativePath"></param>
        /// <param name="p_oPostedFile"></param>
        /// <param name="p_nMaxSize"></param>
        /// <param name="p_bLocalized"></param>
        /// <param name="p_arrContentType"></param>
        /// <returns></returns>
        protected string UploadFile(string p_sRelativePath, System.Web.HttpPostedFile p_oPostedFile, int p_nMaxSize, bool p_bLocalized, params string[] p_arrContentType)
        {
            if ((p_oPostedFile != null) && (p_oPostedFile.ContentLength > 0))
            {
                ArrayList arrContentType = new ArrayList(p_arrContentType);
                if ((arrContentType.Contains(p_oPostedFile.ContentType) || (arrContentType.Count == 0)) && ((p_oPostedFile.ContentLength < p_nMaxSize) || (p_nMaxSize == 0)))
                {
                    string sRoot = System.Web.HttpRuntime.AppDomainAppPath;

                    FileInfo oClientFile = new FileInfo(p_oPostedFile.FileName);
                    string sDataDirectory = GetModuleDataDirectory(default(string), p_sRelativePath, p_bLocalized);
                    string sFileName = Guid.NewGuid().ToString().Replace("-", string.Empty) + oClientFile.Extension;

                    byte[] arrBuffer = new byte[p_oPostedFile.ContentLength];
                    p_oPostedFile.InputStream.Read(arrBuffer, 0, p_oPostedFile.ContentLength);

                    BinaryWriter oWriter = new BinaryWriter(new FileStream(sRoot + sDataDirectory + sFileName, FileMode.Create));
                    oWriter.Write(arrBuffer);
                    oWriter.Close();
                    return sFileName;
                }
                else
                {
                    return string.Empty;
                }
            }
            else
            {
                return string.Empty;
            }
        }



        /// <summary>
        /// Safe with no Exception function, return negative value if error
        /// </summary>
        /// <param name="p_cboObject"></param>
        /// <returns></returns>
        protected int GetComboSelectedValue(DropDownList p_cboObject)
        {
            //int nResult = -1;
            //try
            //{ 
            //    nResult = Convert.ToInt32(p_cboObject.SelectedValue);
            //}
            //catch
            //{
            //}
            //return nResult;
            return ConvertSafe.ToInt32(p_cboObject.SelectedValue);
        }

        protected void BindDataToCombo(DropDownList p_cboObject, Array p_arrData, string p_sTextField, string p_sValueField)
        {
            /*p_cboObject.DataSource = p_oData;
            p_cboObject.DataTextField = p_sTextField;
            p_cboObject.DataValueField = p_sValueField;
            p_cboObject.DataBind();*/

            p_cboObject.Items.Clear();

            if (p_arrData.Length == 0)
            {
                return;
            }

            Type tData = p_arrData.GetValue(0).GetType();
            PropertyInfo oTextProp = tData.GetProperty(p_sTextField);
            PropertyInfo oValueProp = tData.GetProperty(p_sValueField);

            foreach (object oData in p_arrData)
            {
                string sText, sValue;
                if (oTextProp != null)
                {
                    sText = oTextProp.GetValue(oData, null).ToString();
                }
                else
                {
                    try
                    {
                        sText = ((GMetaDTO)oData)[p_sTextField].ToString();
                    }
                    catch
                    {
                        throw new PortalException("Lỗi bind data vào ListBox, DropDownList. Không có thuộc tính " + p_sTextField);
                    }
                }
                if (oValueProp != null)
                {
                    sValue = oValueProp.GetValue(oData, null).ToString();
                }
                else
                {
                    try
                    {
                        sValue = ((GMetaDTO)oData)[p_sValueField].ToString();
                    }
                    catch
                    {
                        throw new PortalException("Lỗi bind data vào ListBox, DropDownList. Không có thuộc tính " + p_sValueField);
                    }
                }

                ListItem itm = new ListItem(sText, sValue);
                p_cboObject.Items.Add(itm);
            }
        }

        protected void BindDataToCombo(DropDownList p_cboObject, Array p_oData, string p_sTextField, string p_sValueField, object p_oDefaultValue)
        {
            /*p_cboObject.DataSource = p_oData;
            p_cboObject.DataTextField = p_sTextField;
            p_cboObject.DataValueField = p_sValueField;
            p_cboObject.DataBind();*/
            BindDataToCombo(p_cboObject, p_oData, p_sTextField, p_sValueField);
            p_cboObject.SelectedIndex = p_cboObject.Items.IndexOf(p_cboObject.Items.FindByValue(p_oDefaultValue.ToString()));
        }

        protected void BindDataToListBox(ListBox p_cboObject, object p_oData, string p_sTextField, string p_sValueField)
        {
            p_cboObject.Items.Clear();
            p_cboObject.DataSource = p_oData;
            p_cboObject.DataTextField = p_sTextField;
            p_cboObject.DataValueField = p_sValueField;
            p_cboObject.DataBind();
        }

        protected void BindDataToListBox(ListBox p_cboObject, object p_oData, string p_sTextField, string p_sValueField, object p_oDefaultValue)
        {
            p_cboObject.Items.Clear();
            p_cboObject.DataSource = p_oData;
            p_cboObject.DataTextField = p_sTextField;
            p_cboObject.DataValueField = p_sValueField;
            p_cboObject.DataBind();
            p_cboObject.SelectedIndex = p_cboObject.Items.IndexOf(p_cboObject.Items.FindByValue(p_oDefaultValue.ToString()));
        }

        protected ArrayList GetListControlKeyValues(ListControl p_cboObject)
        {
            ArrayList arrValue = new ArrayList();

            foreach (ListItem itm in p_cboObject.Items)
            {
                arrValue.Add(ConvertSafe.ToInt32(itm.Value));
            }

            return arrValue;
        }

        #endregion



        #region NAVIGATION MECHANISM

        /// <summary>
		/// MAIN FUNCTION of Navigation Mechanism: get redirect url with parameters
		/// </summary>
		/// <param name="p_sFrom"></param>
		/// <param name="p_sAction"></param>
		/// <param name="p_arrParam">pair of name-value</param>
		/// <returns></returns>
		protected string GetNavigationURLWithParam(string p_sAction, string p_sNavigateParameter, params string[] p_arrParam)
		{
			Hashtable htNavigation = (Hashtable)GURUCORE.Framework.Core.GApplication.GetInstance().GetSharedObject(WebsiteApplication.NAVIGATION_CACHE_KEY);
			WebsiteConfiguration oWebsiteCfg = (WebsiteConfiguration)GURUCORE.Framework.Core.GApplication.GetInstance().GetSharedObject(WebsiteConfiguration.GLOBAL_CACHE_KEY);
			string sPageletClassName = this.GetType().BaseType.FullName;
            

            #region Get the target page base on navigation, pageconfig and parameter           
            

            string sTarget;

			if (string.IsNullOrEmpty(p_sAction) == false)  // calling pagelet raises an action to navigate
			{
                Hashtable htAction = htNavigation[sPageletClassName] as Hashtable;
				if (htAction == null)
				{
#if (OPTIMIZING)
                    throw new PortalException( string.Format("Pagelet {0} have no action defined", sPageletClassName) );
#else
                    return ((GURUCORE.Portal.Core.Controller.PageController)this.Page).PreRewriteRawURL;
#endif
                }



                string sActionWithDefaultParameterInPageConfig = string.Empty;
                if (string.IsNullOrEmpty(p_sNavigateParameter) == true) // fill the navigation parameter of PageConfig, MasterPageConfig
                {
                    sActionWithDefaultParameterInPageConfig = p_sAction + "#" + this.PageletDefine.Parameter;
                    sActionWithDefaultParameterInPageConfig = sActionWithDefaultParameterInPageConfig.TrimEnd('#');
                }
                else   // parameter by programming code
				{
					p_sAction = p_sAction + "#" + p_sNavigateParameter;
                    p_sAction = p_sAction.TrimEnd('#');
				}
                

                /// if target is wrong, we redirect to the original URL, not throw exception
                if (htAction.ContainsKey(sActionWithDefaultParameterInPageConfig))
                {
                    sTarget = (string)htAction[sActionWithDefaultParameterInPageConfig];
                }
                else if (htAction.ContainsKey(p_sAction))
                {
                    sTarget = (string)htAction[p_sAction];
                }
                else
                {
#if (OPTIMIZING)
                    throw new PortalException(
                        string.Format("This pagelet [{0}] is missing its Action [{1}]", sPageletClassName, p_sAction)
                        );
#else
                    return ((GURUCORE.Portal.Core.Controller.PageController)this.Page).PreRewriteRawURL;
#endif
                }
			}
			else    // no action is raised, redirect to current page
			{
				sTarget = this.PageContext.PageURL;
            }

            #endregion





            Hashtable htTargetInParam = GetAllTargetInParam(sTarget);

            // TODO: GURUCORE: these line make our engine can not handle multiple extension
            // if pageextension = .aspx,.php2,. ... then the pagename is in wrong format
			if (!sTarget.EndsWith(oWebsiteCfg.PageExtension))
			{
				sTarget = sTarget + oWebsiteCfg.PageExtension;
			}

			//collect out param
			int nParamCount = p_arrParam.Length / 2;
			for (int nCounter = 0; nCounter < nParamCount; nCounter++)
			{
				string sParamName = p_arrParam[2 * nCounter].ToString();
				string sParamValue = p_arrParam[2 * nCounter + 1].ToString();

				if (htTargetInParam.ContainsKey(sParamName))
				{
					htTargetInParam[sParamName] = sParamValue;
				}
			}

			string sURL = sTarget + "?";
			foreach (DictionaryEntry oEntry in htTargetInParam)
			{
                if (null == oEntry.Value)
				{
					if (this.PageContext.GetSpecial(oEntry.Key) != null)
					{
						sURL += oEntry.Key.ToString() + "=" + this.PageContext.GetSpecial(oEntry.Key).ToString() + "&";
					}
				}
				else
				{
					sURL += oEntry.Key.ToString() + "=" + oEntry.Value.ToString() + "&";
				}
			}

			return sURL.TrimEnd('&','?');
		}
        /// <summary>
        /// wrapper function of GetNavigationURLWithParam()
        /// </summary>
        /// <param name="p_sAction">ACTION name, to match with Navigation config in DB</param>
        /// <param name="p_arrParam">pair of parameter</param>
        /// <returns></returns>
        protected string GetNavigationURL(string p_sAction, params string[] p_arrParam)
        {
            return GetNavigationURLWithParam(p_sAction, null, p_arrParam);
        }


		private Hashtable GetAllTargetInParam(string p_sTarget)
		{
			const string CACHE_PAGE_IN_PARAM = "CachePageInParam";

			Hashtable htAllModule = (Hashtable)GURUCORE.Framework.Core.GApplication.GetInstance().GetSharedObject(WebsiteApplication.MODULE_ASSEMBLY_CACHE_KEY);
			Hashtable htPageParam;

			if (HttpRuntime.Cache[CACHE_PAGE_IN_PARAM + "#" + p_sTarget] != null)
			{
				htPageParam = (Hashtable)HttpRuntime.Cache[CACHE_PAGE_IN_PARAM + "#" + p_sTarget];
				ArrayList arrAllKey = new ArrayList(htPageParam.Keys);
				foreach (string sKey in arrAllKey)
				{
					htPageParam[sKey] = null;
				}
				return htPageParam;
			}
			else
			{
				htPageParam = new Hashtable();

				Hashtable htPageDefinition = (Hashtable)GApplication.GetInstance().GetSharedObject(WebsiteApplication.PAGE_DEFINITION_CACHE_KEY);
				if (htPageDefinition.ContainsKey(p_sTarget))
				{
					DTOCollection<VwPageDefinitionDTO> arrAllPagelet = (DTOCollection<VwPageDefinitionDTO>)htPageDefinition[p_sTarget];

					ArrayList arrProcessed = new ArrayList();
					foreach (VwPageDefinitionDTO dtoPageDef in arrAllPagelet)
					{
						if (arrProcessed.Contains(dtoPageDef.PageletID))
						{
							continue;
						}
						arrProcessed.Add(dtoPageDef.PageletID);
						Assembly oAsm = (Assembly)htAllModule[dtoPageDef.ModuleUniqueID];
						Type oPageletType = oAsm.GetType(dtoPageDef.ClassName);

						if (oPageletType == null)
						{
                            throw new PortalException("Pagelet's Classname is incorrect, or missing bin file (module's dll): " + dtoPageDef.ClassName);
						}
						FieldInfo[] arrAllField = oPageletType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
						foreach (FieldInfo oField in arrAllField)
						{
							object[] arrAllAttribute = oField.GetCustomAttributes(typeof(PageletInParamAttribute), false);
							if (arrAllAttribute.Length == 1)
							{
								PageletInParamAttribute oParamAttr = (PageletInParamAttribute)arrAllAttribute[0];
								if (!oParamAttr.IsShared)
								{
									if (!htPageParam.ContainsKey(dtoPageDef.PageConfigID + oParamAttr.ParamName))
									{
										htPageParam.Add(dtoPageDef.PageConfigID + oParamAttr.ParamName, null);
									}
								}
								else
								{
									if (!htPageParam.ContainsKey(oParamAttr.ParamName))
									{
										htPageParam.Add(oParamAttr.ParamName, null);
									}
								}
							}
						}
					}
				}

				//cache it
				HttpRuntime.Cache.Insert(CACHE_PAGE_IN_PARAM + "#" + p_sTarget, htPageParam, null, DateTime.MaxValue, TimeSpan.Zero);

				return htPageParam;
			}
		}

		private Hashtable GetAllPageletOutParam()
		{
			const string CACHE_PAGELET_OUT_PARAM = "CachePageletOutParam";

			Hashtable htAllModule = (Hashtable)GApplication.GetInstance().GetSharedObject(WebsiteApplication.MODULE_ASSEMBLY_CACHE_KEY);
			Hashtable htPageletOutParamField;
			Hashtable htPageletOutParamValue;

			if (HttpRuntime.Cache[CACHE_PAGELET_OUT_PARAM + "#" + this.GetType().FullName] != null)
			{
				htPageletOutParamField = (Hashtable)HttpRuntime.Cache[CACHE_PAGELET_OUT_PARAM + "#" + this.GetType().FullName];
				htPageletOutParamValue = new Hashtable();
				ArrayList arrAllKey = new ArrayList(htPageletOutParamField.Keys);
				foreach (string sKey in arrAllKey)
				{
					FieldInfo oField = (FieldInfo)htPageletOutParamField[sKey];
					htPageletOutParamValue.Add(sKey, oField.GetValue(this));
				}
				return htPageletOutParamValue;
			}
			else
			{
				htPageletOutParamField = new Hashtable();
				htPageletOutParamValue = new Hashtable();

				Type oPageletType = this.GetType().BaseType;

				FieldInfo[] arrAllField = oPageletType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
				foreach (FieldInfo oField in arrAllField)
				{
					object[] arrAllAttribute = oField.GetCustomAttributes(typeof(PageletOutParamAttribute), false);
					if (arrAllAttribute.Length == 1)
					{
						PageletOutParamAttribute oParamAttr = (PageletOutParamAttribute)arrAllAttribute[0];
						if (oParamAttr.ParamDest == PageletOutParamAttribute.URL_PARAM_DEST)
						{
							if (!htPageletOutParamField.ContainsKey(oParamAttr.ParamName))
							{
								htPageletOutParamField.Add(oParamAttr.ParamName, oField);
								htPageletOutParamValue.Add(oParamAttr.ParamName, oField.GetValue(this));
							}
						}
						else if (oParamAttr.ParamDest == PageletOutParamAttribute.SESSION_PARAM_DEST)
						{
							Session[oParamAttr.ParamName] = oField.GetValue(this);
						}
					}
				}

				//cache it
				HttpRuntime.Cache.Insert(CACHE_PAGELET_OUT_PARAM + "#" + this.GetType().FullName, htPageletOutParamField, null, DateTime.MaxValue, TimeSpan.Zero);

				return htPageletOutParamValue;
			}
		}


		
		
        /// <summary>
        /// Transfer request to page (take by the Navigation DB COnfig, with provided action, with provided NavigateParameter).
        /// </summary>
        /// <param name="p_sAction"></param>
        /// <param name="p_sNavigateParameter"></param>
		public void Navigate(string p_sAction, string p_sNavigateParameter)
		{   
            //collect out param
            Hashtable htOutParam = this.GetAllPageletOutParam();
            System.Collections.Generic.List<string> arrParam = new System.Collections.Generic.List<string>();
            foreach (DictionaryEntry oEntry in htOutParam)
            {
                arrParam.Add(oEntry.Key.ToString());
                if (oEntry.Value != null)
                {
                    arrParam.Add(oEntry.Value.ToString());
                }
                else
                {
                    arrParam.Add(string.Empty);
                }
            }


            string sUrl = this.GetNavigationURLWithParam(p_sAction, p_sNavigateParameter, arrParam.ToArray());            
            Response.Redirect(sUrl, true);
		}
        /// <summary>
        /// Wrap FUNCTION
        /// </summary>
        /// <param name="p_sAction"></param>
        public void Navigate(string p_sAction)
        {            
            this.Navigate(p_sAction, null);
        }




		public void Reload()
		{			
			Response.Redirect(((Controller.PageController)this.Page).PreRewriteRawURL, true);
        }

        #endregion Navigation mechanism








        private Hashtable m_htControl2DTOMapper;
        private Hashtable m_htDTO2ControlMapper;
        /// <summary>
        /// Collect controls on Form to DTO
        /// </summary>
        /// <returns></returns>
        protected virtual Hashtable SetupControl2DTOMapper()
        {
            List<Control2DTOMapperInfo> arrFromXML = GApplication.GetInstance().GetSharedObject<List<Control2DTOMapperInfo>>(WebsiteApplication.AUTO_COLLECT_CONTROL_2_DTO_CACHE_KEY);
            Hashtable htProp = new Hashtable();
            foreach (Control2DTOMapperInfo info in arrFromXML)
            {
                Type tMapper = Type.GetType("GURUCORE.Portal.Core.Pagelet+" + info.MapperName);
                object oMapper = Activator.CreateInstance(tMapper, info.ControlPrefix, info.PropertyName, this);
                htProp.Add(info.ControlName, oMapper);
            }

            return htProp;
        }

        /// <summary>
        /// Bind from DTO to control on form
        /// </summary>
        /// <returns></returns>
        protected virtual Hashtable SetupDTO2ControlMapper()
        {
            List<DTO2ControlMapperInfo> arrFromXML = GApplication.GetInstance().GetSharedObject<List<DTO2ControlMapperInfo>>(WebsiteApplication.AUTO_COLLECT_DTO_2_CONTROL_CACHE_KEY);
            Hashtable htProp = new Hashtable();
            foreach (DTO2ControlMapperInfo info in arrFromXML)
            {
                Type tMapper = Type.GetType("GURUCORE.Portal.Core.Pagelet+" + info.MapperName);
                object oMapper = Activator.CreateInstance(tMapper, info.ControlPrefix, info.PropertyName, this);
                htProp.Add(info.ControlName, oMapper);
            }

            return htProp;
        }

		#region Automated data collector

        protected virtual void OnAutoCollectData(DTOBase p_dtoData, Control p_ctrlContainer)
        {

        }


		protected DTOBase AutoCollectData(DTOBase p_dtoData, Control p_ctrlContainer, bool p_bCallCustomCollect)
		{
			PropertyInfo[] arrProp = p_dtoData.GetType().GetProperties();

			Stack<Control> stkControl = new Stack<Control>();
			foreach (Control oCtrl in p_ctrlContainer.Controls)
			{
				stkControl.Push(oCtrl);
			}

			//object dtoInstance = Activator.CreateInstance(p_tDTOType);
			while (stkControl.Count > 0)
			{
				Control oCtrl = stkControl.Pop();

				if (! ((oCtrl is Repeater) || (oCtrl is DataList) || (oCtrl is GridView) || (oCtrl is DataGrid)))
				{
					foreach (Control oSubCtrl in oCtrl.Controls)
					{
						stkControl.Push(oSubCtrl);
					}
				}

				Control2DTOMapper oMapper = (Control2DTOMapper)m_htControl2DTOMapper[oCtrl.GetType().FullName];
				if (oMapper != null)
				{
					oMapper.Map(oCtrl, p_dtoData);
				}
			}
			if (p_bCallCustomCollect)
			{
				OnAutoCollectData(p_dtoData, p_ctrlContainer);
			}
			return p_dtoData;
		}
	

		protected T AutoCollectData<T>(Control p_ctrlContainer) where T : DTOBase
		{
			object dtoInstance = Activator.CreateInstance(typeof(T));
			return (T)AutoCollectData((DTOBase)dtoInstance, p_ctrlContainer, true);
		}


        [System.Diagnostics.DebuggerStepThrough()]
        public abstract class Control2DTOMapper
		{
			protected Pagelet m_oPagelet;
			protected string m_sControlPrefix;
			protected string m_sProperty;

			public Control2DTOMapper(string p_sControlPrefix, string p_sProperty, Pagelet p_oPagelet)
			{
				m_oPagelet = p_oPagelet;
				m_sControlPrefix = p_sControlPrefix;
				m_sProperty = p_sProperty;
			}

			public abstract void Map(Control p_oCtrl, object p_dtoData);
		}

		public class SimpleControl2DTOMapper : Control2DTOMapper
		{
			public SimpleControl2DTOMapper(string p_sControlPrefix, string p_sProperty, Pagelet p_oPagelet) : base(p_sControlPrefix, p_sProperty,p_oPagelet)
			{

			}

			public override void Map(Control p_oCtrl, object p_dtoData)
			{
				Type tControlType = p_oCtrl.GetType();

				if (p_oCtrl.ID.StartsWith(m_sControlPrefix))
				{
					string sName = p_oCtrl.ID.Substring(m_sControlPrefix.Length);
					PropertyInfo oControlProp = tControlType.GetProperty(m_sProperty);
					PropertyInfo oDTOProp = p_dtoData.GetType().GetProperty(sName);
					if (oDTOProp != null)
					{
						try
						{
							object oCtrlValue = Convert.ChangeType(oControlProp.GetValue(p_oCtrl, null), oDTOProp.PropertyType);
							oDTOProp.SetValue(p_dtoData, oCtrlValue, null);
						}
						catch
						{

						}
					}
				}
			}
		};

        public class FileUploadControl2DTOMapper : Control2DTOMapper
		{
			public FileUploadControl2DTOMapper(string p_sControlPrefix, string p_sPropertyName, Pagelet p_oPagelet) : base(p_sControlPrefix, "PostedFile", p_oPagelet)
			{
			}

			public override void Map(Control p_oCtrl, object p_dtoData)
			{
				Type tControlType = p_oCtrl.GetType();

				if (p_oCtrl.ID.StartsWith(m_sControlPrefix))
				{
					string sName = p_oCtrl.ID.Substring(m_sControlPrefix.Length);
					PropertyInfo oControlProp = tControlType.GetProperty(m_sProperty);
					PropertyInfo oDTOProp = p_dtoData.GetType().GetProperty(sName);

					HttpPostedFile oPostedFile = (HttpPostedFile)oControlProp.GetValue(p_oCtrl, null);
                    if (null != oPostedFile && oPostedFile.ContentLength > 0)
					{
						try
						{
							string sDataPath = m_oPagelet.UploadFile(string.Empty, oPostedFile, 0, false);
							oDTOProp.SetValue(p_dtoData, sDataPath, null);
						}
						catch
						{
						}							
					}
				}
			}
		}

        #endregion Automated data collector


		#region Automated data binder

		protected void AutoBindData(DTOBase p_dtoData, Control p_ctrlContainer, bool p_bCallCustomBind)
		{
			if (p_dtoData == null)
			{
				return;
			}
			Type tDTO = p_dtoData.GetType();
			PropertyInfo[] arrProp = tDTO.GetProperties();

			ArrayList arrControl = new ArrayList();

			Stack<Control> stkCtrl = new Stack<Control>();
			foreach (Control oCtrl in p_ctrlContainer.Controls)
			{
				stkCtrl.Push(oCtrl);
			}

			while (stkCtrl.Count > 0)
			{
				Control oCtrl = stkCtrl.Pop();

				arrControl.Add(oCtrl);

                if (!((oCtrl is GridView) || (oCtrl is DataList) || (oCtrl is DataGrid) || (oCtrl is Repeater)))
                {
                    foreach (Control oSubControl in oCtrl.Controls)
                    {
                        stkCtrl.Push(oSubControl);
                    }
                }

				DTO2ControlMapper oMapper = (DTO2ControlMapper)m_htDTO2ControlMapper[oCtrl.GetType().FullName];
				if (oMapper != null)
				{
					oMapper.Map(oCtrl,p_dtoData);
				}
			}

			if (p_bCallCustomBind)
			{
				OnAutoBindData(p_dtoData, p_ctrlContainer);
			}
		}

		protected virtual void OnAutoBindData(DTOBase p_dtoData, Control p_ctrlContainer)
		{

		}



        [System.Diagnostics.DebuggerStepThrough()]
        public abstract class DTO2ControlMapper
        {
            protected Pagelet m_oPagelet;
            protected string m_sControlPrefix;
            protected string m_sProperty;

            public DTO2ControlMapper(string p_sControlPrefix, string p_sProperty, Pagelet p_oPagelet)
            {
                m_oPagelet = p_oPagelet;
                m_sControlPrefix = p_sControlPrefix;
                m_sProperty = p_sProperty;
            }

            public abstract void Map(Control p_oCtrl, DTOBase p_dtoData);
        }

        public sealed class SimpleDTO2ControlMapper : DTO2ControlMapper
        {
            public SimpleDTO2ControlMapper(string p_sControlPrefix, string p_sProperty, Pagelet p_oPagelet)
                : base(p_sControlPrefix, p_sProperty, p_oPagelet)
            {

            }

            public override void Map(Control p_oCtrl, DTOBase p_dtoData)
            {
                Type tControlType = p_oCtrl.GetType();
                Type tDTOType = p_dtoData.GetType();

                if (p_oCtrl.ID.StartsWith(m_sControlPrefix))
                {
                    string sName = p_oCtrl.ID.Substring(m_sControlPrefix.Length);
                    PropertyInfo oControlProp = tControlType.GetProperty(m_sProperty);
                    if (p_dtoData is GMetaDTO)
                    {
                        if (((GMetaDTO)p_dtoData).Field[sName] != null)
                        {
                            object oDTOFieldValue = Convert.ChangeType(((GMetaDTO)p_dtoData).Field[sName], oControlProp.PropertyType);
                            if (oDTOFieldValue != null)
                            {
                                oControlProp.SetValue(p_oCtrl, oDTOFieldValue, null);
                            }
                        }
                    }
                    else
                    {
                        PropertyInfo oDTOProp = tDTOType.GetProperty(sName);
                        if ((oDTOProp != null) && (!p_dtoData.IsNull(sName)))
                        {
                            object oDTOFieldValue = Convert.ChangeType(oDTOProp.GetValue(p_dtoData, null), oControlProp.PropertyType);
                            if (oDTOFieldValue != null)
                            {
                                oControlProp.SetValue(p_oCtrl, oDTOFieldValue, null);
                            }
                        }
                    }
                }
            }
        };

        public sealed class ImageDTO2ControlMapper : DTO2ControlMapper
        {
            public ImageDTO2ControlMapper(string p_sControlPrefix, string p_sPropertyName, Pagelet p_oPagelet)
                : base(p_sControlPrefix, "ImageUrl", p_oPagelet)
            {
            }

            public override void Map(Control p_oCtrl, DTOBase p_dtoData)
            {
                Type tControlType = p_oCtrl.GetType();
                Type tDTOType = p_dtoData.GetType();

                if (p_oCtrl.ID.StartsWith(m_sControlPrefix))
                {
                    string sName = p_oCtrl.ID.Substring(m_sControlPrefix.Length);
                    PropertyInfo oControlProp = tControlType.GetProperty(m_sProperty);

                    if (p_dtoData is GMetaDTO)
                    {
                        if (((GMetaDTO)p_dtoData).Field[sName] != null)
                        {
                            object oDTOFieldValue = Convert.ChangeType(((GMetaDTO)p_dtoData).Field[sName], oControlProp.PropertyType);
                            if (oDTOFieldValue != null)
                            {
                                string sImageLink = m_oPagelet.GetDataLink(string.Empty, oDTOFieldValue.ToString(), false);
                                oControlProp.SetValue(p_oCtrl, oDTOFieldValue, null);
                            }
                        }
                    }
                    else
                    {
                        PropertyInfo oDTOProp = tDTOType.GetProperty(sName);
                        if (oDTOProp != null)
                        {
                            object oDTOFieldValue = oDTOProp.GetValue(p_dtoData, null);
                            if (oDTOFieldValue != null)
                            {
                                string sImageLink = m_oPagelet.GetDataLink(string.Empty, oDTOFieldValue.ToString(), false);
                                oControlProp.SetValue(p_oCtrl, sImageLink, null);
                            }
                            else
                            {
                                tControlType.GetProperty("Visible").SetValue(p_oCtrl, false, null);
                            }
                        }
                    }
                }
            }
        }

        public sealed class ComboDTO2ControlMapper : DTO2ControlMapper
        {
            public ComboDTO2ControlMapper(string p_sControlPrefix, Pagelet p_oPagelet)
                : base(p_sControlPrefix, "", p_oPagelet)
            {
            }

            public override void Map(Control p_oCtrl, DTOBase p_dtoData)
            {
                Type tControlType = p_oCtrl.GetType();
                Type tDTOType = p_dtoData.GetType();

                if (p_oCtrl.ID.StartsWith(m_sControlPrefix))
                {
                    string sName = p_oCtrl.ID.Substring(m_sControlPrefix.Length);
                    PropertyInfo oControlProp = tControlType.GetProperty(m_sProperty);

                    if (p_dtoData is GMetaDTO)
                    {
                        if (((GMetaDTO)p_dtoData).Field[sName] != null)
                        {
                            object oDTOFieldValue = Convert.ChangeType(((GMetaDTO)p_dtoData).Field[sName], oControlProp.PropertyType);
                            if (oDTOFieldValue != null)
                            {
                                ListItem oItem = ((DropDownList)p_oCtrl).Items.FindByValue(oDTOFieldValue.ToString());
                                ((DropDownList)p_oCtrl).SelectedIndex = ((DropDownList)p_oCtrl).Items.IndexOf(oItem);
                            }
                        }
                    }
                    else
                    {
                        PropertyInfo oDTOProp = tDTOType.GetProperty(sName);
                        if (oDTOProp != null)
                        {
                            object oDTOFieldValue = oDTOProp.GetValue(p_dtoData, null);
                            if (oDTOFieldValue != null)
                            {
                                ListItem oItem = ((DropDownList)p_oCtrl).Items.FindByValue(oDTOFieldValue.ToString());
                                ((DropDownList)p_oCtrl).SelectedIndex = ((DropDownList)p_oCtrl).Items.IndexOf(oItem);
                            }
                        }
                    }
                }
            }
        }

		#endregion Automated data binder

		



		



        #region FOR DATA-LISTING-TYPE pagelets



        private class DataListControlInfo
        {
            private bool m_bEnableEL;

            public bool EnableEL
            {
                get { return m_bEnableEL; }
                set { m_bEnableEL = value; }
            }


            private string m_sKeyField;

            public DataListControlInfo()
            {
                m_htCommand = new Hashtable();
            }

            public string KeyField
            {
                get { return m_sKeyField; }
                set { m_sKeyField = value; }
            }

            private Hashtable m_htCommand;

            public Hashtable Command
            {
                get { return m_htCommand; }
                set { m_htCommand = value; }
            }

            private FieldInfo m_oListActionTargetField;

            public FieldInfo ListActionTargetField
            {
                get { return m_oListActionTargetField; }
                set { m_oListActionTargetField = value; }
            }

        }

        private Hashtable m_htListCommandRegister = new Hashtable();





        #region GridView

        /// <summary>
        /// Tell the grid which is the keyfield. When a row selected, keyfield value will set to the TargetField (marked with ListActionTargetAttribute)
        /// </summary>
        /// <param name="p_grdGrid"></param>
        /// <param name="p_sKeyField"></param>
        protected void RegisterGridView(GridView p_grdGrid, string p_sKeyField)
        {
            FieldInfo[] arrFieldInfo = this.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
            FieldInfo oTargetField = null;

            foreach (FieldInfo oFieldInfo in arrFieldInfo)
            {
                object[] arrAttrb = oFieldInfo.GetCustomAttributes(typeof(ListActionTargetAttribute), false);
                foreach (ListActionTargetAttribute oAttrb in arrAttrb)
                {
                    if (oAttrb.ListID == p_grdGrid.ID)
                    {
                        oTargetField = oFieldInfo;
                        break;
                    }
                }

                if (oTargetField != null)
                {
                    break;
                }
            }

            if (oTargetField == null)
            {
                throw new PortalException(m_sPageletName + "inherits GridPagelet, and it must have a Field marked with ListActionTargetAttribute");
            }


            if (m_htListCommandRegister.ContainsKey(p_grdGrid.ID))
            {
                ((DataListControlInfo)m_htListCommandRegister[p_grdGrid.ID]).KeyField = p_sKeyField;
                ((DataListControlInfo)m_htListCommandRegister[p_grdGrid.ID]).ListActionTargetField = oTargetField;
            }
            else
            {
                DataListControlInfo oInfo = new DataListControlInfo();
                oInfo.KeyField = p_sKeyField;
                oInfo.ListActionTargetField = oTargetField;
                m_htListCommandRegister.Add(p_grdGrid.ID, oInfo);
            }

            p_grdGrid.RowDataBound += new GridViewRowEventHandler(p_grdGrid_RowDataBound);
            p_grdGrid.RowCommand += new GridViewCommandEventHandler(p_grdGrid_RowCommand);
        }


        protected virtual void OnGridRowBinding(GridView p_grdSender, GridViewRow p_oRow, DTOBase p_dtoData)
        {

        }

        protected void p_grdGrid_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            GridView grdSender = (GridView)sender;
            if (e.Row.RowType == DataControlRowType.DataRow)  // only process DataRow, do not process DataHeader, ...
            {
                object dtoData = e.Row.DataItem;

                this.AutoBindData((DTOBase)dtoData, e.Row, false);
                OnGridRowBinding(grdSender, e.Row, (DTOBase)dtoData);

                if (m_htListCommandRegister.ContainsKey(grdSender.ID))
                {
                    //ArrayList arrCommand = (ArrayList)((DataListControlInfo)m_htListCommandRegister[grdSender.ID]).Command.Keys;
                    string sKey = ((DataListControlInfo)m_htListCommandRegister[grdSender.ID]).KeyField;
                    
                    //if (string.IsNullOrEmpty(sKey))
                    //{
                    //    throw new PortalException("GridView " + grdSender.ID + "does not have KeyField");
                    //}

                    // assign the value of keyfield in dtoData (data of current selected row in listing view) --> all button's commandArgument
                    foreach (string sCommand in ((DataListControlInfo)m_htListCommandRegister[grdSender.ID]).Command.Keys)
                    {
                        Control oCtrl = e.Row.FindControl("btn" + sCommand.Substring(1));
                                                
                        if (oCtrl is Button)
                        {
                            ((Button)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                        else if (oCtrl is LinkButton)
                        {
                            ((LinkButton)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                        else if (oCtrl is ImageButton)
                        {
                            ((LinkButton)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                    }
                    
                }
            }
        }

        protected void p_grdGrid_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            GridView grdSender = (GridView)sender;
            int nObjectID;
            if (int.TryParse(e.CommandArgument as string, out nObjectID) == false)
            {
                return;
                //throw new PortalException("Một pagelet kế thừa GridPagelet phải khai báo một trường khoá cho gridview. Trong hàm tạo, thêm đoạn mã sau:\r\n\this.Key=[Tên trường khoá]");
            }

            DataListControlInfo oDataListControlInfo = (DataListControlInfo)m_htListCommandRegister[grdSender.ID];

            // set value to the marked field
            oDataListControlInfo.ListActionTargetField.SetValue(this, nObjectID);

            //call some On handlers (before navigate)
            MethodInfo oGeneralMethod = this.GetType().GetMethod("OnGridCommand", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
            if (oGeneralMethod != null)
            {
                object[] arrParam = new object[] { grdSender, e.CommandName, nObjectID };
                oGeneralMethod.Invoke(this, arrParam);
            }

            MethodInfo oMethod = this.GetType().GetMethod("OnGridCommand" + e.CommandName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
            if (oMethod != null)
            {
                object[] arrParam = new object[] { grdSender, nObjectID };
                oMethod.Invoke(this, arrParam);
            }

            //do navigation
            if (oDataListControlInfo.Command[e.CommandName] != null)
            {
                this.Navigate(oDataListControlInfo.Command[e.CommandName].ToString());
            }

        }



        /// <summary>
        /// G: util function, assign datasource to grid control.
        /// </summary>
        /// <param name="p_grdGrid"></param>
        /// <param name="p_oDataSource"></param>
        protected void BindDataToGridView(GridView p_grdGrid, object p_oDataSource)
        {
            p_grdGrid.DataSource = p_oDataSource;
            p_grdGrid.DataBind();
        }

        #endregion


        #region DataList

        protected void RegisterDataList(DataList p_dtlList, string p_sKeyField)
        {
            FieldInfo[] arrFieldInfo = this.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
            FieldInfo oTargetField = null;
            foreach (FieldInfo oFieldInfo in arrFieldInfo)
            {
                object[] arrAttrb = oFieldInfo.GetCustomAttributes(typeof(ListActionTargetAttribute), false);
                /*if (arrAttrb.Length > 0)
                {
                    m_oActionIDTargetField = oFieldInfo;
                    break;
                }*/
                foreach (ListActionTargetAttribute oAttrb in arrAttrb)
                {
                    if (oAttrb.ListID == p_dtlList.ID)
                    {
                        oTargetField = oFieldInfo;
                        break;
                    }
                }
                if (oTargetField != null)
                {
                    break;
                }
            }

            if (oTargetField == null)
            {
                //throw new PortalException("GridPagelet cần phải khai báo một biến cục bộ có gán attribute ActionIDTarget");
            }

            //find binding controller
            string sListName = p_dtlList.ID;
            bool bEnableEL = false;
            if (sListName.Length > 3)
            {
                FieldInfo oBindingController = this.GetType().GetField("bdc" + sListName.Substring(3), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
                if (oBindingController != null)
                {
                    bEnableEL = ((GURUCORE.Portal.AspNet.Control.BindingController)oBindingController.GetValue(this)).EnableEL;
                }
            }

            if (m_htListCommandRegister.ContainsKey(p_dtlList.ID))
            {
                ((DataListControlInfo)m_htListCommandRegister[p_dtlList.ID]).KeyField = p_sKeyField;
                ((DataListControlInfo)m_htListCommandRegister[p_dtlList.ID]).ListActionTargetField = oTargetField;
                ((DataListControlInfo)m_htListCommandRegister[p_dtlList.ID]).EnableEL = bEnableEL;
            }
            else
            {
                DataListControlInfo oInfo = new DataListControlInfo();
                oInfo.KeyField = p_sKeyField;
                oInfo.ListActionTargetField = oTargetField;
                oInfo.EnableEL = bEnableEL;
                m_htListCommandRegister.Add(p_dtlList.ID, oInfo);
            }


            p_dtlList.ItemDataBound += new DataListItemEventHandler(p_lstList_ItemDataBound);
            p_dtlList.ItemCommand += new DataListCommandEventHandler(p_lstList_ItemCommand);
        }


        /// <summary>
        /// G: register (add) an action for a listcontrol command. When that command is run, Messio will navigate with registered action.
        /// </summary>
        /// <param name="p_sListControlID"></param>
        /// <param name="p_sCommand"></param>
        /// <param name="p_sAction"></param>
        protected void RegisterListControlCommand(string p_sListControlID, string p_sCommand, string p_sAction)
        {
            if (m_htListCommandRegister.ContainsKey(p_sListControlID))
            {
                if (((DataListControlInfo)m_htListCommandRegister[p_sListControlID]).Command.ContainsKey(p_sCommand))
                {
                    ((DataListControlInfo)m_htListCommandRegister[p_sListControlID]).Command[p_sCommand] = p_sAction;
                }
                else
                {
                    ((DataListControlInfo)m_htListCommandRegister[p_sListControlID]).Command.Add(p_sCommand, p_sAction);
                }
            }
            else
            {
                DataListControlInfo oInfo = new DataListControlInfo();
                oInfo.Command[p_sCommand] = p_sAction;
                m_htListCommandRegister.Add(p_sListControlID, oInfo);
            }
        }

        protected virtual void OnListItemBinding(DataList p_dtlSender, DataListItem p_oItem, DTOBase p_dtoData)
        {

        }

        void p_lstList_ItemCommand(object source, DataListCommandEventArgs e)
        {
            DataList dtlSender = (DataList)source;
            int nObjectID;
            try
            {
                nObjectID = Convert.ToInt32(e.CommandArgument);
            }
            catch // (Exception ex)
            {
                return;
                //throw new PortalException("Một pagelet kế thừa ListPagelet phải khai báo một trường khoá cho datalist. Trong hàm tạo, thêm đoạn mã sau:\r\n\tthis.Key=[Tên trường khoá]");
            }

            if (((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).ListActionTargetField != null)
            {
                ((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).ListActionTargetField.SetValue(this, nObjectID);
            }

            //call handlers
            MethodInfo oGeneralMethod = this.GetType().GetMethod("OnListCommand", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
            if (oGeneralMethod != null)
            {
                object[] arrParam = new object[] { dtlSender, e.Item, e.CommandName, nObjectID };
                oGeneralMethod.Invoke(this, arrParam);
            }

            MethodInfo oMethod = this.GetType().GetMethod("OnListCommand" + e.CommandName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
            if (oMethod != null)
            {
                object[] arrParam = new object[] { dtlSender, e.Item, nObjectID };
                oMethod.Invoke(this, arrParam);
            }

            //do navigation
            this.Navigate(((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).Command[e.CommandName].ToString());
        }

        void p_lstList_ItemDataBound(object sender, DataListItemEventArgs e)
        {
            DataList dtlSender = (DataList)sender;
            if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
            {
                if ((m_htListCommandRegister.ContainsKey(dtlSender.ID)) && (((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).EnableEL == false))
                {
                    object dtoData = e.Item.DataItem;

                    this.AutoBindData((DTOBase)dtoData, e.Item, false);

                    OnListItemBinding(dtlSender, e.Item, (DTOBase)dtoData);

                    //ArrayList arrCommand = (ArrayList)((DataListControlInfo)m_htListCommandRegister[grdSender.ID]).Command.Keys;
                    string sKey = ((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).KeyField;
                    foreach (string sCommand in ((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).Command.Keys)
                    {
                        Control oCtrl = e.Item.FindControl("btn" + sCommand.Substring(1));

                        if (oCtrl is Button)
                        {
                            ((Button)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                        else if (oCtrl is LinkButton)
                        {
                            ((LinkButton)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                        else if (oCtrl is ImageButton)
                        {
                            ((ImageButton)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// G: util function. assign datasource to datalist control.
        /// </summary>
        /// <param name="p_lstList"></param>
        /// <param name="p_oDataSource"></param>
        protected void BindDataToDataList(DataList p_lstList, object p_oDataSource)
        {
            p_lstList.DataSource = p_oDataSource;
            p_lstList.DataBind();
        }

        #endregion


        #region Repeater

        protected void RegisterRepeater(Repeater p_Lister, string p_sKeyField)
        {
            FieldInfo[] arrFieldInfo = this.GetType().BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
            FieldInfo oTargetField = null;
            foreach (FieldInfo oFieldInfo in arrFieldInfo)
            {
                object[] arrAttrb = oFieldInfo.GetCustomAttributes(typeof(ListActionTargetAttribute), false);
                /*if (arrAttrb.Length > 0)
                {
                    m_oActionIDTargetField = oFieldInfo;
                    break;
                }*/
                foreach (ListActionTargetAttribute oAttrb in arrAttrb)
                {
                    if (oAttrb.ListID == p_Lister.ID)
                    {
                        oTargetField = oFieldInfo;
                        break;
                    }
                }
                if (oTargetField != null)
                {
                    break;
                }
            }

            if (oTargetField == null)
            {
                //throw new PortalException("GridPagelet cần phải khai báo một biến cục bộ có gán attribute ActionIDTarget");
            }

            //find binding controller
            string sListName = p_Lister.ID;
            bool bEnableEL = false;
            if (sListName.Length > 3)
            {
                FieldInfo oBindingController = this.GetType().GetField("bdc" + sListName.Substring(3), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
                if (oBindingController != null)
                {
                    bEnableEL = ((GURUCORE.Portal.AspNet.Control.BindingController)oBindingController.GetValue(this)).EnableEL;
                }
            }

            if (m_htListCommandRegister.ContainsKey(p_Lister.ID))
            {
                ((DataListControlInfo)m_htListCommandRegister[p_Lister.ID]).KeyField = p_sKeyField;
                ((DataListControlInfo)m_htListCommandRegister[p_Lister.ID]).ListActionTargetField = oTargetField;
                ((DataListControlInfo)m_htListCommandRegister[p_Lister.ID]).EnableEL = bEnableEL;
            }
            else
            {
                DataListControlInfo oInfo = new DataListControlInfo();
                oInfo.KeyField = p_sKeyField;
                oInfo.ListActionTargetField = oTargetField;
                oInfo.EnableEL = bEnableEL;
                m_htListCommandRegister.Add(p_Lister.ID, oInfo);
            }


            p_Lister.ItemDataBound += new RepeaterItemEventHandler(p_Lister_ItemDataBound);
            p_Lister.ItemCommand += new RepeaterCommandEventHandler(p_Lister_ItemCommand);
        }

        void p_Lister_ItemCommand(object source, RepeaterCommandEventArgs e)
        {
            DataList dtlSender = (DataList)source;
            int nObjectID;
            try
            {
                nObjectID = Convert.ToInt32(e.CommandArgument);
            }
            catch // (Exception ex)
            {
                return;
                //throw new PortalException("Một pagelet kế thừa ListPagelet phải khai báo một trường khoá cho datalist. Trong hàm tạo, thêm đoạn mã sau:\r\n\tthis.Key=[Tên trường khoá]");
            }

            if (((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).ListActionTargetField != null)
            {
                ((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).ListActionTargetField.SetValue(this, nObjectID);
            }

            //call handlers
            MethodInfo oGeneralMethod = this.GetType().GetMethod("OnListCommand", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
            if (oGeneralMethod != null)
            {
                object[] arrParam = new object[] { dtlSender, e.Item, e.CommandName, nObjectID };
                oGeneralMethod.Invoke(this, arrParam);
            }

            MethodInfo oMethod = this.GetType().GetMethod("OnListCommand" + e.CommandName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
            if (oMethod != null)
            {
                object[] arrParam = new object[] { dtlSender, e.Item, nObjectID };
                oMethod.Invoke(this, arrParam);
            }

            //do navigation
            this.Navigate(((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).Command[e.CommandName].ToString());
        }

        void p_Lister_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            Repeater dtlSender = sender as Repeater;
            if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
            {
                if ((m_htListCommandRegister.ContainsKey(dtlSender.ID)) && (((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).EnableEL == false))
                {
                    object dtoData = e.Item.DataItem;

                    this.AutoBindData((DTOBase)dtoData, e.Item, false);

                    OnRepeaterItemBinding(dtlSender, e.Item, (DTOBase)dtoData);

                    //ArrayList arrCommand = (ArrayList)((DataListControlInfo)m_htListCommandRegister[grdSender.ID]).Command.Keys;
                    string sKey = ((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).KeyField;
                    foreach (string sCommand in ((DataListControlInfo)m_htListCommandRegister[dtlSender.ID]).Command.Keys)
                    {
                        Control oCtrl = e.Item.FindControl("btn" + sCommand.Substring(1));

                        if (oCtrl is Button)
                        {
                            ((Button)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                        else if (oCtrl is LinkButton)
                        {
                            ((LinkButton)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                        else if (oCtrl is ImageButton)
                        {
                            ((ImageButton)oCtrl).CommandArgument = dtoData.GetType().GetProperty(sKey).GetValue(dtoData, null).ToString();
                        }
                    }
                }
            }
        }

        protected virtual void OnRepeaterItemBinding(Repeater p_Lister, RepeaterItem p_oItem, DTOBase p_dtoData)
        {

        }
        
        /// <summary>
        /// G: util function. Assign datasource to repeater control
        /// </summary>
        /// <param name="p_Lister"></param>
        /// <param name="p_oDataSource"></param>
        protected void BindDataToRepeater(Repeater p_Lister, object p_oDataSource)
        {
            p_Lister.DataSource = p_oDataSource;
            p_Lister.DataBind();
        }

        #endregion


        #endregion FOR DATA-LISTING-TYPE pagelets




    }   // end class pagelet


}   // end namespace
